package com.niiwoo.civet.trade.service.dubbo.creditor;

import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.niiwoo.civet.trade.dao.entity.ProjectInvestOrder;
import com.niiwoo.civet.trade.dto.response.creditor.*;
import com.niiwoo.civet.trade.service.local.invest.InvestOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.PageInfo;
import com.niiwoo.civet.trade.dao.entity.CreditorSaleBatch;
import com.niiwoo.civet.trade.dao.entity.CreditorSaleDetail;
import com.niiwoo.civet.trade.dto.request.creditor.CancelCreditorSaleRequestDTO;
import com.niiwoo.civet.trade.dto.request.creditor.CreditorSaleApplyRequestDTO;
import com.niiwoo.civet.trade.dto.request.creditor.CreditorSaleOrderPageRequestDTO;
import com.niiwoo.civet.trade.dto.request.creditor.CreditorValidateRequestDTO;
import com.niiwoo.civet.trade.service.creditor.CreditorSaleOrderDubboService;
import com.niiwoo.civet.trade.service.local.creditor.CreditorSaleOrderCancelService;
import com.niiwoo.civet.trade.service.local.creditor.CreditorSaleOrderInitService;
import com.niiwoo.civet.trade.service.local.creditor.CreditorSaleOrderService;
import com.niiwoo.civet.trade.service.local.creditor.TradableInvestOrderService;
import com.niiwoo.civet.trade.utils.RepaymentUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service(version = "1.0.0")
public class CreditorSaleOrderDubboServiceImpl implements CreditorSaleOrderDubboService {
	@Autowired
	private CreditorSaleOrderService creditorSaleOrderService;
	@Autowired
	private CreditorSaleOrderInitService creditorSaleOrderInitService;
	@Autowired
	private CreditorSaleOrderCancelService creditorSaleOrderCancelService;
	@Autowired
	private TradableInvestOrderService tradableInvestOrderService;
    @Autowired
    private InvestOrderService investOrderService;
	
	public PageCreditorSaleBatchOrderDTO getUserAllCreditorBatchSaleOrderByPage(CreditorSaleOrderPageRequestDTO request) {
        List<CreditorSaleBatch> list = creditorSaleOrderService.getUserCreditorSaleBatchOrderPage(request);
        PageInfo<CreditorSaleBatch> pageInfo = new PageInfo(list);
		
		PageCreditorSaleBatchOrderDTO result = new PageCreditorSaleBatchOrderDTO();
		List<CreditorSaleBatchOrderDTO> items = null;
		if (list != null && !list.isEmpty()) {
			items = new ArrayList<>();
			
			List<CreditorSaleDetailOrderSimpleDTO> detailDtos = null;
			List<CreditorSaleDetail> details = null;
			CreditorSaleBatchOrderDTO batchDto = null;
			
			for (CreditorSaleBatch batch : list) {
				batchDto = new CreditorSaleBatchOrderDTO();
				batchDto.setCreateTime(batch.getCreateTime());
				batchDto.setCreditorSaleBatchId(batch.getId());
				batchDto.setDetailCount(batch.getDetailCount());
				batchDto.setSaleAmount(batch.getSaleAmount());
				
				details = creditorSaleOrderService.getCreditorSaleDetailOrderByBatchId(request.getUserId(), batch.getId());
				if (details == null || details.isEmpty()) continue;
				
				detailDtos = new ArrayList<>();
				for (CreditorSaleDetail detail : details) {
					if (detail == null) continue;
					
					detailDtos.add(parseCreditorSaleDetailOrderSimpleDTO(detail));
				}
				batchDto.setDetails(detailDtos);
				
				items.add(batchDto);
			}
		}
		
		result.setItems(items);
		result.setTotalCount((int) pageInfo.getTotal());
		result.setTotalPage(pageInfo.getPages());
		
		return result;
	}
	
	public PageCreditorSaleDetailOrderDTO getUserAllCreditorDetailSaleOrderByPage(CreditorSaleOrderPageRequestDTO request) {
        List<CreditorSaleDetail> list = creditorSaleOrderService.getUserCreditorSaleDetailOrderPage(request);
        PageInfo<CreditorSaleBatch> pageInfo = new PageInfo(list);
		
		PageCreditorSaleDetailOrderDTO result = new PageCreditorSaleDetailOrderDTO();
		List<CreditorSaleDetailOrderDTO> items = null;
		if (list != null && !list.isEmpty()) {
			items = new ArrayList<>();
			
			CreditorSaleDetailOrderDTO detailDto = null;
			CreditorSaleBatch batchOrder = null;
			for (CreditorSaleDetail detail : list) {
				detailDto = parseCreditorSaleDetailOrderDTO(detail);
				batchOrder = creditorSaleOrderService.getCreditorSaleBatchOrderById(request.getUserId(), detail.getBatchId());
				if (batchOrder != null) {
					detailDto.setIsBatch(batchOrder.getIsBatch() == null || batchOrder.getIsBatch() == 0 ? (byte)0 : (byte)1);
				}
				
				items.add(detailDto);
			}
		}
		
		result.setItems(items);
		result.setTotalCount((int) pageInfo.getTotal());
		result.setTotalPage(pageInfo.getPages());
		
		return result;
	}

	public CreditorSaleBatchOrderDTO getCreditorSaleBatchOrder(String userId, Long creditorSaleBatchId) {
		CreditorSaleBatchOrderDTO result = null;
		
		CreditorSaleBatch batch = creditorSaleOrderService.getCreditorSaleBatchOrderById(userId, creditorSaleBatchId);
		
		if (batch == null) return null;
		
		result = new CreditorSaleBatchOrderDTO();
		result.setCreateTime(batch.getCreateTime());
		result.setCreditorSaleBatchId(batch.getId());
		result.setDetailCount(batch.getDetailCount());
		result.setSaleAmount(batch.getSaleAmount());
		
		List<CreditorSaleDetail> details = creditorSaleOrderService.getCreditorSaleDetailOrderByBatchId(userId, batch.getId());
		if (details != null && !details.isEmpty()) {
			List<CreditorSaleDetailOrderSimpleDTO> detailDtos = new ArrayList<>();
			
			for (CreditorSaleDetail detail : details) {
				if (detail == null) continue;
				
				detailDtos.add(parseCreditorSaleDetailOrderSimpleDTO(detail));
			}
			
			result.setDetails(detailDtos);
		}
		
		return result;
	}

	public CreditorSaleDetailOrderDTO getCreditorSaleDetailOrder(String saleUserId, Long creditorSaleDetailId) {
		CreditorSaleDetail detail = creditorSaleOrderService.getCreditorSaleDetailOrder(saleUserId, creditorSaleDetailId);
		
		if (detail == null) return null;
		
		CreditorSaleDetailOrderDTO result = parseCreditorSaleDetailOrderDTO(detail);
		
		CreditorSaleBatch batchOrder = creditorSaleOrderService.getCreditorSaleBatchOrderById(saleUserId, detail.getBatchId());
		if (batchOrder != null) {
			result.setIsBatch(batchOrder.getIsBatch() == null || batchOrder.getDetailCount() == 0 ? (byte)0 : (byte)1);
		}
		
		return result;
	}
	
	private CreditorSaleDetailOrderSimpleDTO parseCreditorSaleDetailOrderSimpleDTO(CreditorSaleDetail detail) {
		if (detail == null) return null;
		
		CreditorSaleDetailOrderSimpleDTO result = new CreditorSaleDetailOrderSimpleDTO();
		result.setCreditorSaleBatchId(detail.getBatchId());
		result.setCreditorSaleDetailId(detail.getId());
		result.setDeadline(detail.getDeadline());
		result.setRemainingMonth(detail.getRemainingDeadlineMonth());
		// 剩余天数 - (当前日期 - 创建时间)  即使借款人还款后且在还款日发起债转申请也不会将剩余天数置为0
		result.setRemainingDay(detail.getRemainingDeadlineDay() - RepaymentUtil.getOverdueDay(detail.getCreateTime(), getRemainDayEndTime(detail)));
		result.setSaleAmount(detail.getSaleAmount().add(detail.getSellingInterest()).setScale(2, RoundingMode.HALF_EVEN));
		result.setCreateTime(detail.getCreateTime());
		result.setBorrowRate(detail.getBorrowRate());
		result.setStatus(parseCreditorSaleDetailStatus(detail.getStatus(), detail.getEndType()));
		
		return result;
	}
	
	private CreditorSaleDetailOrderDTO parseCreditorSaleDetailOrderDTO(CreditorSaleDetail detail) {
		// 重新计算相关费用
		tradableInvestOrderService.reCalcAmount(detail);
		
		CreditorSaleDetailOrderDTO result = new CreditorSaleDetailOrderDTO();
		result.setCreditorSaleBatchId(detail.getBatchId());
		result.setCreditorSaleDetailId(detail.getId());
		result.setUserId(detail.getUserId());
		result.setDeadline(detail.getDeadline());
		result.setRemainingMonth(detail.getRemainingDeadlineMonth());
		// 剩余天数 - (当前日期 - 创建时间)  即使借款人还款后且在还款日发起债转申请也不会将剩余天数置为0
		result.setRemainingDay(detail.getRemainingDeadlineDay() - RepaymentUtil.getOverdueDay(detail.getCreateTime(), getRemainDayEndTime(detail)));
		result.setSaleAmount(detail.getSaleAmount().add(detail.getSellingInterest()).setScale(2, RoundingMode.HALF_EVEN));
		result.setCreateTime(detail.getCreateTime());
		result.setBorrowRate(detail.getBorrowRate());
		result.setArrivalAmount(detail.getArrivalAmount());
		result.setExpenseAmount(detail.getExpenseAmount().add(detail.getSellingExpenseAmount()).setScale(2, RoundingMode.HALF_EVEN));
		result.setOffAmount(detail.getOffAmount());
		result.setEndTime(parseCreditorSaleDetailEndTime(detail));
		result.setStatus(parseCreditorSaleDetailStatus(detail.getStatus(), detail.getEndType()));
		
		return result;
	}
	
	private Byte parseCreditorSaleDetailStatus(Byte orderStatus, Byte endType) {
		//状态；1-转让中,2-已撤销,3-已过期,4-成功,5-失败(用户还款)
		switch (orderStatus) {//状态：0-转让申请中，1-转让中，2-认购中，3-交易处理中（债权转让）4-转让成功，5-已结束(失败)
		case 0:
			return (byte)1; //0-转让申请中
		case 1:
			return (byte)1; //1-转让中
		case 2:
			return (byte)1; //2-认购中
		case 3:
			return (byte)1; //3-交易处理中（债权转让
		case 4:
			return (byte)4; //4-成功
		case 5:
			switch (endType) {//结束类型：0-初始，1-用户撤销，2-已过期，3-用户还款,4-其他
			case 1:
				return (byte)2; //2-已撤销
			case 2:
				return (byte)3; //3-已过期
			case 3:
				return (byte)5; //5-失败(用户还款)
			case 0:
			default:
				break;
			}
		default:
			break;
		}
		return null;
	}
	
	private Date parseCreditorSaleDetailEndTime(CreditorSaleDetail detail) {
		switch (detail.getStatus()) {//状态：0-转让申请中，1-转让中，2-认购中，3-交易处理中（债权转让）4-转让成功，5-已结束(失败)
		case 0:
			return detail.getExpireTime(); //过期时间
		case 1:
			return detail.getExpireTime(); //过期时间
		case 2:
			return detail.getExpireTime(); //过期时间
		case 3:
			return detail.getExpireTime(); //过期时间
		case 4:
			return detail.getSuccessTime(); //成功时间
		case 5:
			switch (detail.getEndType()) {//结束类型：0-初始，1-用户撤销，2-已过期，3-用户还款,4-其他
			case 2:
				return detail.getExpireTime(); //过期时间
			case 0:
			case 1:
			case 3:
			default:
				return detail.getEndTime(); //结束时间
			}
		default:
			break;
		}
		return null;
	}
	
	private Date getRemainDayEndTime(CreditorSaleDetail detail) {
		Date currentDate = new Date();
		switch (detail.getStatus()) {//状态：0-转让申请中，1-转让中，2-认购中，3-交易处理中（债权转让）4-转让成功，5-已结束(失败)
		case 0:
		case 1:
		case 2:
		case 3:
			return currentDate; //过期时间
		case 4:
			return detail.getSuccessTime(); //成功时间
		case 5:
			switch (detail.getEndType()) {//结束类型：0-初始，1-用户撤销，2-已过期，3-用户还款,4-其他
			case 2:
				return detail.getExpireTime(); //过期时间
			case 0:
			case 1:
			case 3:
			default:
				return detail.getEndTime(); //结束时间
			}
		default:
			break;
		}
		return null;
	}

	@Override
	public void validateSaleCreditor(CreditorValidateRequestDTO requestDTO){
		Assert.notNull(requestDTO, "数据对象不可空");
		Assert.notNull(requestDTO.getUserId(), "用户ID不能为空");
		Assert.notNull(requestDTO.getInvestOrderId(), "投资订单Id不可空");
		creditorSaleOrderInitService.validateSaleCreditor(requestDTO);
	}

	@Override
	public CreditorSaleApplyResponseDTO creditorSaleApply(CreditorSaleApplyRequestDTO requestDTO){
		Assert.notNull(requestDTO, "参数对象不可空");
		Assert.notEmpty(requestDTO.getCreditorSaleApplyDetailDTOList(), "债权出让详情不能为空");
		return creditorSaleOrderInitService.creditorSaleApply(requestDTO);
	}
	@Override
	public void preCreditorSaleApply(CreditorSaleApplyRequestDTO requestDTO) {
		Assert.notNull(requestDTO, "参数对象不可空");
		Assert.notEmpty(requestDTO.getCreditorSaleApplyDetailDTOList(), "债权出让详情不能为空");
		creditorSaleOrderInitService.preCreditorSaleApply(requestDTO);
	}

	@Override
	public void cancelCreditorSale(CancelCreditorSaleRequestDTO requestDTO) {
		Assert.notNull(requestDTO.getUserId(), "用户ID不能为空");
		Assert.notEmpty(requestDTO.getCreditorSaleDetailIdList(), "债权出让订单ID列表不能为空");
		Assert.notNull(requestDTO.getEndTypeEnum(), "取消类型为空");
		for (Long creditorSaleDetailId : requestDTO.getCreditorSaleDetailIdList()) {
			creditorSaleOrderCancelService.cancelCreditorSaleOrder(creditorSaleDetailId, requestDTO.getUserId(),
					requestDTO.getEndTypeEnum());
		}
	}

	@Override
	public void autoCancelCreditorSale() {
		creditorSaleOrderCancelService.autoCancelCreditorSale();
	}

	@Override
	public void debentureSaleCompensation() {
		creditorSaleOrderInitService.debentureSaleCompensation();
	}
	
	@Override
	public void cancelDebentureSaleCompensation() {
		creditorSaleOrderCancelService.cancelDebentureSaleCompensation();
	}

	@Override
	public void deleteSelloutCreditorOrder() {
		creditorSaleOrderInitService.deleteSelloutCreditorOrder();
	}

	/**
	 * 账单-获取债转剩余天数、月
	 * @param investOrderId 投资订单ID
	 * @param refundOrderDetailId 还款/垫付订单明细ID
	 * @return
	 */
	@Override
	public CreditorTransferRemainingDayAndMonthDTO getTransferRemainingDayAndMonth(Long investOrderId,Long refundOrderDetailId) {
        CreditorTransferRemainingDayAndMonthDTO remainingDayAndMonthDTO = new CreditorTransferRemainingDayAndMonthDTO();

        if (investOrderId == null && refundOrderDetailId != null) {
            // 根据refundOrderDetailId查询investOrderId
            investOrderId = investOrderService.getInvestIdByRefundDetailId(refundOrderDetailId);
        }

        // 查询投资订单，获取 creditor_sale_detail_id，creditor_sale_user_id
        ProjectInvestOrder investOrder = investOrderService.getInvestByInvestOrderId(investOrderId);
        if (investOrder != null) {
            Long creditorSaleDetailId = investOrder.getCreditorSaleDetailId();
            String creditorSaleUserId = investOrder.getCreditorSaleUserId();
            // 查询债权出让明细订单表，获取剩余天数，剩余月份
            CreditorSaleDetail creditorSaleDetail =  creditorSaleOrderService.getCreditorSaleDetailOrder(creditorSaleUserId,creditorSaleDetailId);
            remainingDayAndMonthDTO.setRemainingDay(creditorSaleDetail.getRemainingDeadlineDay());
            remainingDayAndMonthDTO.setRemainingMonth(creditorSaleDetail.getRemainingDeadlineMonth());
            remainingDayAndMonthDTO.setUserId(creditorSaleUserId);
            remainingDayAndMonthDTO.setCreditorSaleDetailId(creditorSaleDetailId);
        }

        return remainingDayAndMonthDTO;
	}
}